package cn.com.lyb.aspect;

import cn.com.lyb.annotation.RedissionLock;
import cn.com.lyb.core.exception.BizException;
import cn.com.lyb.utils.SpElUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 接口幂等性
 */
@Aspect
@Component
public class RedissionAspect {
    private static final Logger logger = LoggerFactory.getLogger(RedissionAspect.class);

    @Autowired
    private RedissonClient redissonClient;

    @Around("@annotation(redissionLock)")
    public Object lock(ProceedingJoinPoint proceedingJoinPoint, RedissionLock redissionLock) {

        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        String key = SpElUtils.parseSpEl(method, proceedingJoinPoint.getArgs(), redissionLock.keyPrefix());

        String lockKey = String.format("lock:%s:%s", key, redissionLock.type());
        RLock lock = redissonClient.getLock(lockKey);
        boolean hasLock = false;
        try {
            hasLock = lock.tryLock(redissionLock.waitTime(), redissionLock.expire(), redissionLock.timeUnit());
            if (hasLock) {
                return proceedingJoinPoint.proceed();
            }
        } catch (Throwable throwable) {
            logger.error(throwable.getMessage());
            throw new BizException(throwable.getMessage());
        } finally {
            if (hasLock) {
                lock.unlock();
            }
        }
        throw new BizException("获取分布式锁失败");
    }
}

